package com.dolphin.aiagentplatform.utils;

import com.dolphin.aiagentplatform.model.vo.user.UserVO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 * 提供JWT令牌的生成和解析功能
 */
@Slf4j
@Component
public class JwtUtils {

    /**
     * 令牌前缀
     */
    private static final String TOKEN_PREFIX = "Bearer ";
    /**
     * 密钥
     */
    private Key key;
    /**
     * 令牌有效期（默认30分钟）
     */
    private long tokenValidityInMilliseconds = 30 * 60 * 1000;

    /**
     * 默认秘钥和有效期初始化
     */
    @PostConstruct
    public void init() {
        if (this.key == null) {
            this.key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
            log.info("已初始化默认JWT密钥");
        }
        log.info("JWT令牌有效期: {}分钟", this.tokenValidityInMilliseconds / 60 / 1000);
    }

    /**
     * 注入配置的JWT秘钥
     *
     * @param secretKey 配置的秘钥
     */
    @Value("${jwt.secret:}")
    public void setSecretKey(String secretKey) {
        // 如果配置了自定义秘钥，就使用配置的秘钥
        if (secretKey != null && !secretKey.isEmpty()) {
            this.key = Keys.hmacShaKeyFor(secretKey.getBytes());
            log.info("已加载配置的JWT密钥");
        }
    }

    /**
     * 注入配置的令牌有效期
     *
     * @param tokenValidity 配置的有效期（分钟）
     */
    @Value("${jwt.token-validity-in-minutes:30}")
    public void setTokenValidity(int tokenValidity) {
        this.tokenValidityInMilliseconds = (long) tokenValidity * 60 * 1000;
        log.info("已设置JWT令牌有效期: {}分钟", tokenValidity);
    }

    /**
     * 创建令牌
     *
     * @param userVO 用户信息
     * @return 令牌
     */
    public String createToken(UserVO userVO) {
        long now = System.currentTimeMillis();
        Date validity = new Date(now + this.tokenValidityInMilliseconds);

        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userVO.getId());
        claims.put("username", userVO.getUsername());
        claims.put("role", userVO.getRole());

        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userVO.getId().toString())
                .setIssuedAt(new Date(now))
                .setExpiration(validity)
                .signWith(this.key)
                .compact();
    }

    /**
     * 解析令牌
     *
     * @param token 令牌
     * @return 解析后的Claims
     */
    public Claims parseToken(String token) {
        try {
            // 移除Bearer前缀
            if (token != null && token.startsWith(TOKEN_PREFIX)) {
                token = token.substring(7);
            }

            return Jwts.parserBuilder()
                    .setSigningKey(this.key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            log.error("JWT解析失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从令牌中获取用户ID
     *
     * @param token 令牌
     * @return 用户ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = parseToken(token);
        return claims != null ? Long.valueOf(claims.getSubject()) : null;
    }

    /**
     * 验证令牌是否有效
     *
     * @param token 令牌
     * @return 是否有效
     */
    public boolean validateToken(String token) {
        try {
            Claims claims = parseToken(token);
            return claims != null && claims.getExpiration().after(new Date());
        } catch (Exception e) {
            log.error("JWT验证失败: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 获取完整的认证头值
     *
     * @param token JWT令牌
     * @return 带前缀的认证头值
     */
    public String getAuthHeader(String token) {
        if (token != null && !token.startsWith(TOKEN_PREFIX)) {
            return TOKEN_PREFIX + token;
        }
        return token;
    }
} 